package org.valire.db;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 
 * @author Daniel Orr
 *
 */
public class SqlExecutor extends JdbcDaoSupport {

	private static Logger logger = LoggerFactory.getLogger(SqlExecutor.class);
	private TransactionTemplate transactionTemplate;

	public void setTransactionManager(PlatformTransactionManager txManager) {
		transactionTemplate = new TransactionTemplate(txManager);
		transactionTemplate
				.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
	}

	/**
	 * Executes all statements in script in a single transaction.
	 * 
	 * @param script
	 */
	public void executeScript(File scriptFile) {
		try {
			String scriptContent = FileUtils.readFileToString(scriptFile);
			executeScript(scriptContent);
		} catch (IOException e) {
			logger.error("Could not read file {}", scriptFile.getAbsoluteFile(), e);
		}
	}
	/**
	 * Executes all statements in script in a single transaction.
	 * 
	 * @param script
	 */
	public void executeScript(final String scriptContent) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			public void doInTransactionWithoutResult(TransactionStatus status) {
				String[] statements = StringUtils.split(scriptContent, ";");
				executeStatements(statements);
			}
		});
	}

	/**
	 * Executes all statements in a single transaction.
	 * 
	 * @param script
	 */
	public void executeStatements(final String[] statements) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			public void doInTransactionWithoutResult(TransactionStatus status) {
				for (String statement : statements) {
					String s = StringUtils.trim(statement);
					if (!s.isEmpty()) {
						logger.debug("\tExecuting statement:\n\t'{}'", s);
						getJdbcTemplate().execute(statement);
					}
				}
			}
		});
	}

	/**
	 * Executes the given statement in a transaction.
	 * 
	 * @param statement
	 */
	public void executeStatement(final String statement) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			public void doInTransactionWithoutResult(TransactionStatus status) {
				String s = StringUtils.trim(statement);
				if (!s.isEmpty()) {
					logger.debug("\tExecuting statement:\n\t'{}'", s);
					getJdbcTemplate().execute(statement);
				}
			}
		});
	}

	public int queryForInt(String sql) throws DataAccessException {
		return getJdbcTemplate().queryForInt(sql);
	}
	
}
